﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SCG.SolarVengeanceEngine;
using SCG.TurboSprite;
using SCG.General;
using SCG.TurboSprite.SquareGrid;
using SCG.SolarVengeanceEngine.StarShips;
using SCG.WinForms;
using System.IO;

namespace SCG.SolarVengeance
{
    public partial class GamePage : BasePage, ISVHost, ISVCustomRenderer
    {
        //constructors
        public GamePage()
            : base()
        {
            InitializeComponent();
            _instance = this;
        }

        //singleton instance
        private static GamePage _instance;
        public static GamePage Instance
        {
            get
            {
                return _instance;
            }
        }

        //access game instance
        public SVGame Game
        {
            get
            {
                return MainForm.Game;
            }
        }

        //access cursor location
        public SCGPoint CursorLocation
        {
            get
            {
                return new SCGPoint(surface.CursorX, surface.CursorY);
            }
        }

        //The sound flag
        private SoundFlag _sound;
        public SoundFlag SoundFlag
        {
            get
            {
                return _sound;
            }
            set
            {
                if (value > _sound)
                    _sound = value;
            }
        }

        //initialize
        private Cursor TargetCursor;
        public override void Initialize()
        {
            surface.CellsX = Game.Width;
            surface.CellsY = Game.Height;
            miniMap.Game = Game; 
            lblMessage.Text = "";
            pnlMessage.Visible = false;
            TargetCursor = new Cursor("Target.cur");
            foreach (Control ctl in pnlStarSystemsAttacked.Controls)
            {
                ctl.Visible = false;
                ctl.Tag = null;
            }
            _victoryMessage = "";
            _victoryFont = new Font(MainForm.FontFamily, 30);
            btnPause.Visible = !Game.IsMultiPlayer;
            btnResume.Visible = false;
            btnSave.Visible = false;
            lblPlayerStatus.Visible = false;
            btnChat.Visible = Game.CurrentPlayer != null;
            btnAlliance.Visible = Game.CurrentPlayer != null;
            pnlTop.Refresh();

            //compose background tiles
            _starfieldTiles = new Image[Game.Width, Game.Height];
            BuildTerrainMap();

            //clear previous sprites
            engineImages.Clear();
            engineShips.Clear();
            engineSystems.Clear();

            //create starsystem sprites
            foreach (StarSystem system in Game.StarSystems)
            {
                StarSystemSprite ss = new StarSystemSprite(system);
                system.Tag = ss;
                PositionSprite(system, ss);
                engineSystems.AddSprite(ss);
            }

            //create starship sprites
            foreach (StarShip ship in Game.StarShips)
            {
                StarShipSprite ss = new StarShipSprite(ship);
                ship.Tag = ss;
                PositionSprite(ship, ss);
                engineShips.AddSprite(ss);
            }

            //create scenario image sprites
            foreach (ScenarioImage si in Game.ScenarioImages)
            {
                Bitmap bmp = (Bitmap)si.Image;
                BitmapSprite bs = new BitmapSprite(bmp);
                si.Tag = bs;
                bs.Position = new Point(si.X * Constants.CellSize + bmp.Width / 2 - Constants.CellHalf, si.Y * Constants.CellSize + bmp.Height / 2 - Constants.CellHalf);
                engineImages.AddSprite(bs);
            }

            //create wormhole sprites
            foreach (Wormhole wh in Game.Wormholes)
            {
                WormholeSprite ws = new WormholeSprite(wh, _wormHoleImage);
                wh.Tag = ws;
                ws.SpinSpeed = _rnd.Next(5) + 1;
                ws.Spin = SpinType.Clockwise;
                PositionSprite(wh, ws);
                engineSystems.AddSprite(ws);
            }

            //create pulsar sprites
            foreach (Pulsar p in Game.Pulsars)
            {
                PulsarSprite ps = new PulsarSprite(p, _pulsarImage);
                p.Tag = ps;
                PositionSprite(p, ps);
                engineSystems.AddSprite(ps);
            }

            //create black hole sprites
            foreach (BlackHole bh in Game.BlackHoles)
            {
                BlackHoleSprite bs = new BlackHoleSprite(bh);
                bh.Tag = bs;
                PositionSprite(bh, bs);
                engineSystems.AddSprite(bs);
            }

            //create UDO sprites
            foreach (UDO udo in Game.UDOs)
            {
                CreateUDOSprite(udo);
            }

            //activate surface
            surface.Active = true;

            //center on capital
            if (Game.CurrentPlayer != null)
            {
                StarSystem cap = Game.CurrentPlayer.Capital;
                if (cap != null)
                {
                    CenterStarSystem(cap);
                }
                else
                {
                    //center on first owned starsystem
                    StarSystem owned = null;
                    foreach(StarSystem sys in Game.StarSystems)
                        if (sys.OwnedByCurrentPlayer)
                        {
                            owned = sys;
                            break;
                        }
                    if (owned != null)
                    {
                        surface.CenterOnCell(owned.X, owned.Y);
                        surface.CursorX = owned.X;
                        surface.CursorY = owned.Y;
                        SystemSelected = owned;
                        _pnlSystem.ImpulseUpdate();
                        SidePanelMode = SidePanels.StarSystem;
                    }
                    else
                    {
                        //center on first starship
                        if (Game.CurrentPlayer.StarShips.Count > 0)
                        {
                            StarShip ship = Game.CurrentPlayer.StarShips[0];
                            surface.CenterOnCell(ship.X, ship.Y);
                            surface.CursorX = ship.X;
                            surface.CursorY = ship.Y;
                            ShipsSelected.Add(ship);
                            _pnlShip.ImpulseUpdate();
                            SidePanelMode = SidePanels.StarShip;
                        }
                    }
                }
            }
        }
        private void CreateUDOSprite(UDO udo)
        {
            Bitmap bmp = (Bitmap)Bitmap.FromFile("Images\\UDOs\\" + udo.ImageFileName + ".bmp");
            bmp.MakeTransparent(Color.Black);
            UDOSprite udos = new UDOSprite(udo, bmp);
            udo.Tag = udos;
            PositionSprite(udo, udos);
            engineSystems.AddSprite(udos);
        }

        //build the terrain map
        private void BuildTerrainMap()
        {
            for (int x = 0; x < Game.Width; x++)
                for (int y = 0; y < Game.Height; y++)
                {
                    char c = Game.GetTerrain(x, y);
                    if (c == ' ' || c == 'n')
                        _starfieldTiles[x, y] = _starfield.RandomValue;
                    else
                        _starfieldTiles[x, y] = _nebula.RandomValue;
                }
        }

        //position a sprite
        private void PositionSprite(SVMapObject svm, Sprite s)
        {
            s.Position = new Point(svm.X * Constants.CellSize + Constants.CellHalf, svm.Y * Constants.CellSize + Constants.CellHalf);
        }
        private Point GetSpritePosition(SVMapObject svm)
        {
            return new Point(svm.X * Constants.CellSize + Constants.CellHalf, svm.Y * Constants.CellSize + Constants.CellHalf);
        }

        //selected starsystem
        public StarSystem SystemSelected { get; set; }

        //selected starships
        private StarShipList _selectedShips = new StarShipList();
        public StarShipList ShipsSelected
        {
            get
            {
                return _selectedShips;
            }
        }

        //Orders tokenizer
        public List<string> MyOrders
        {
            get
            {
                return _myOrders;
            }
        }

        //process incoming game chat
        public void GameChat(Player p, ChatChannel channel, string msg)
        {
            btnChat.BackColor = Color.White;
            btnChat.Refresh();
            _pnlChat.GameChat(p, channel, msg);
        }

        //submit an order
        public void SubmitOrder(OrderType ot, params object[] parameters)
        {
            SVTokenizer tok = new SVTokenizer(Game);
            tok.AppendToken(ot);
            tok.Tokenize(parameters);
            _myOrders.Add(tok.Result);
            PlaySubmitOrderSound(ot);
        }
        public void SubmitPatrolOrder(StarShip ship)
        {
            SVTokenizer tok = new SVTokenizer(Game);
            tok.AppendToken(OrderType.Patrol);
            tok.AppendToken(ship);
            tok.AppendToken(Waypoints.Count);
            foreach (SCGPoint pt in Waypoints)
            {
                tok.AppendToken(pt.X);
                tok.AppendToken(pt.Y);
            }
            _myOrders.Add(tok.Result);
            PlaySubmitOrderSound(OrderType.Patrol);
        }
        public void SubmitTransportOrder(StarShip ship)
        {
            SVTokenizer tok = new SVTokenizer(Game);
            tok.AppendToken(OrderType.Transport);
            tok.AppendToken(ship);
            tok.AppendToken(TransportPoints[TransportPoints.Count - 1]);
            tok.AppendToken(TransportPoints.Count - 1);
            for(int i = 0; i < TransportPoints.Count - 1; i++)
                tok.AppendToken(TransportPoints[i]);
            _myOrders.Add(tok.Result);
            PlaySubmitOrderSound(OrderType.Transport);
        }
        private long _orderSoundTicks = 0;
        private void PlaySubmitOrderSound(OrderType ot)
        {
            switch (ot)
            {
                case OrderType.BuildStarShip:
                case OrderType.ClearOrders:
                case OrderType.CreateGate:
                case OrderType.Defend:
                case OrderType.DefendPoint:
                case OrderType.Detonate:
                case OrderType.EjectUDO:
                case OrderType.Escort:
                case OrderType.GravRelease:
                case OrderType.Launch:
                case OrderType.Move:
                case OrderType.Patrol:
                case OrderType.SetViewPoint:
                case OrderType.ShipBuildStarShip:
                case OrderType.TargetMapObject:
                case OrderType.TargetStarShip:
                case OrderType.TargetStarSystem:
                case OrderType.Transport:
                case OrderType.TugRelease:
                case OrderType.Unload:
                    PlaySoundExclusive("OrderSubmitted");
                    break;
                case OrderType.BuildShield:
                case OrderType.BuildScanner:
                    PlaySoundExclusive("BuildShieldScanner");
                    break;
            }
        }
        private void PlaySoundExclusive(string soundName)
        {
            long now = DateTime.Now.Ticks;
            if (now - _orderSoundTicks > 100)
            {
                _orderSoundTicks = now;
                MainForm.PlaySound(soundName);
            }
        }

        //show a side panel
        private SidePanels _sidePanelMode = SidePanels.Blank;
        private BasePanel _sidePanel = null;
        public SidePanels SidePanelMode
        {
            get
            {
                return _sidePanelMode;
            }
            set
            {
                if (value == SidePanels.StarSystem)
                    PlaySoundExclusive("StarSystemSelected");
                else if (value == SidePanels.StarShip)
                    PlaySoundExclusive("StarShipSelected");

                if (_sidePanelMode == value)
                {
                    if (_sidePanel != null)
                        _sidePanel.ImpulseUpdate();
                    if (SidePanelMode == SidePanels.StarShip || SidePanelMode == SidePanels.Command)
                        surface.Cursor = ShipsSelected[0].OwnedByCurrentPlayer ? TargetCursor : Cursors.Arrow;
                    else
                        surface.Cursor = Cursors.Arrow;
                    return;
                }
                if (_sidePanel != null)
                    pnlRight.Controls.Remove(_sidePanel);
                _sidePanelMode = value;
                switch (_sidePanelMode)
                {
                    case SidePanels.Blank:
                        ClearSelectedShips();
                        _sidePanel = null;
                        break;
                    case SidePanels.StarSystem:
                        ClearSelectedShips();
                        _sidePanel = _pnlSystem;
                        break;
                    case SidePanels.StarShip:
                        _sidePanel = _pnlShip;
                        break;
                    case SidePanels.Build:
                        ClearSelectedShips();
                        _pnlBuild.BuildMode = BuildMode.BuildFromStarSystem;
                        _sidePanel = _pnlBuild;
                        break;
                    case SidePanels.StarShipBuild:
                        _pnlBuild.BuildMode = BuildMode.BuildFromStarShip;
                        _sidePanel = _pnlBuild;
                        break;
                    case SidePanels.SetAutoBuildStarShip:
                        ClearSelectedShips();
                        _pnlBuild.BuildMode = BuildMode.SetAutoBuildStarShip;
                        _sidePanel = _pnlBuild;
                        break;
                    case SidePanels.Info:
                        ClearSelectedShips();
                        _sidePanel = _pnlInfo;
                        break;
                    case SidePanels.Command:
                        _sidePanel = _pnlCommand;
                        break;
                    case SidePanels.Communications:
                        ClearSelectedShips();
                        _sidePanel = _pnlChat;
                        break;
                    case SidePanels.Alliances:
                        ClearSelectedShips();
                        _sidePanel = _pnlAlliances;
                        break;
                    case SidePanels.QuitConfirm:
                        ClearSelectedShips();
                        _sidePanel = _pnlExit;
                        break;
                    default:
                        throw new ArgumentException("Unexpected SidePanel: " + _sidePanelMode);
                }
                if (_sidePanel != null)
                {
                    _sidePanel.Anchor = AnchorStyles.None;
                    pnlRight.Controls.Add(_sidePanel);
                    _sidePanel.Width = pnlRight.Width;
                    _sidePanel.Height = pnlRight.Height - miniMap.Height;
                    _sidePanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom;
                    _sidePanel.Initialize();
                    _sidePanel.ImpulseUpdate();
                }

                //target cursor
                if (SidePanelMode == SidePanels.StarShip || SidePanelMode == SidePanels.Command)
                    surface.Cursor = ShipsSelected[0].OwnedByCurrentPlayer ? TargetCursor : Cursors.Arrow;
                else
                    surface.Cursor = Cursors.Arrow;
            }
        }
        public BasePanel SidePanel
        {
            get
            {
                return _sidePanel;
            }
        }

        //impulse updated
        private string _victoryMessage = "";
        private Brush _victoryBrush = null;
        private Font _victoryFont = null;
        public void ImpulseUpdated(int impulse)
        {
            if (SoundFlag != SoundFlag.None)
                MainForm.PlaySound(SoundFlag.ToString());
            _sound = SoundFlag.None;

            lblImpulse.Text = "Impulse: " + impulse;
            lblImpulse.Refresh();
            if (Game.CurrentPlayer == null)
                lblTechMultiple.Visible = false;
            else
            {
                lblTechMultiple.Visible = true;
                lblTechMultiple.Text = "Tech Multiple: " + Game.CurrentPlayer.TechMultiple.ToString("N2");
                lblTechMultiple.Refresh();
            }
            miniMap.Refresh();
            if (SidePanel != null)
                SidePanel.ImpulseUpdate();

            //dim starsystem attacked buttons
            foreach(Control ctl in pnlStarSystemsAttacked.Controls)
                if (ctl.Visible)
                {
                    Button btn = ctl as Button;
                    byte r = btn.ForeColor.R;
                    byte g = btn.ForeColor.G;
                    r -= 10;
                    if (g > 0)
                        g -= 10;
                    if (r < 20)
                    {
                        btn.Visible = false;
                        btn.Tag = null;
                    }
                    else
                    {
                        Color c = Color.FromArgb(r, g, 0);
                        btn.ForeColor = c;
                        btn.FlatAppearance.BorderColor = c;
                        btn.Refresh();
                    }
                }

            //are we the winenr?
            bool endGame = false;
            if (Game.CurrentPlayer != null && Game.CurrentPlayer.Victor)
            {
                endGame = true;
                _victoryBrush = PenBrushFactory.GetBrush(new SCGColor(0, 255, 0));
                _victoryMessage = "V I C T O R Y !";

                //the first allied player in the list should report the victory
                if (Game.IsMultiPlayer)
                    foreach(Player p in Game.Players)
                        if (p.Victor && p.IsHuman)
                        {
                            if (p == Game.CurrentPlayer)
                            {
                                Tokenizer tok = new Tokenizer();
                                tok.AppendToken(Game.Scenario.Name);
                                tok.AppendToken(Game.Players.Count);
                                foreach (Player gp in Game.Players)
                                {
                                    tok.AppendToken(gp.Name);
                                    tok.AppendToken(gp.IsHuman);
                                    tok.AppendToken(gp.Victor);
                                }
                                string details = tok.Result;
                                MainForm.Prism.CustomCommand("SVGameEnded", details);
                            }
                            break;
                        }
            }
            //were we defeated
            else if (Game.CurrentPlayer != null && Game.CurrentPlayer.Eliminated)
            {
                endGame = true;
                _victoryBrush = PenBrushFactory.GetBrush(SCGColor.Red);
                _victoryMessage = "D E F E A T E D !";
            }
            //did someone win?
            string victors = "";
            string conj = "is";
            foreach(Player p in Game.Players)
                if (p.Victor)
                {
                    endGame = true;
                    if (victors != "")
                    {
                        victors += ", ";
                        conj = "are";
                    }
                    victors += p.Name;
                }
            if (victors != "")
                DisplayMessage(victors + " " + conj + " Victorious!", true, Color.Lime);
            if (endGame)
                MainForm.GameCoordinator.Stop();
        }

        //switch to starship command mode with specified order type
        public void EnterCommandMode(OrderType ot)
        {
            _pnlCommand.OrderType = ot;
            SidePanelMode = SidePanels.Command;
        }

        //access Waypoints
        public List<SCGPoint> Waypoints
        {
            get
            {
                return _waypoints;
            }
        }

        //access transport points
        public List<SVMapObject> TransportPoints
        {
            get
            {
                return _transportPoints;
            }
        }

        //private members
        private RandomList<Image> _starfield = new RandomList<Image>();
        private RandomList<Image> _nebula = new RandomList<Image>();
        private Image[,] _starfieldTiles;
        private List<string> _myOrders = new List<string>();
        private Bitmap _wormHoleImage;
        private Bitmap _pulsarImage;
        private Bitmap _waypointImage;
        private Random _rnd = new Random();
        private List<SCGPoint> _waypoints = new List<SCGPoint>();
        private List<SVMapObject> _transportPoints = new List<SVMapObject>();

        private StarSystemPanel _pnlSystem;
        private StarShipPanel _pnlShip;
        private BuildStarShipPanel _pnlBuild;
        private InfoPanel _pnlInfo;
        private CommandPanel _pnlCommand;
        private ChatPanel _pnlChat;
        private AlliancePanel _pnlAlliances;
        private ExitGamePanel _pnlExit;

        //form load - one time setup
        private void GamePage_Load(object sender, EventArgs e)
        {
            surface.CellWidth = Constants.CellSize;
            surface.CellHeight = Constants.CellSize;
            surface.CursorColor = Color.FromArgb(128, Color.Yellow);
            _wormHoleImage = (Bitmap)Bitmap.FromFile("Images\\Wormhole.bmp");
            _wormHoleImage.MakeTransparent(Color.Black);
            _pulsarImage = (Bitmap)Bitmap.FromFile("Images\\Pulsar.bmp");
            _waypointImage = (Bitmap)Bitmap.FromFile("Images\\Waypoint.bmp");
            _waypointImage.MakeTransparent(Color.Black);
            dlgSave.InitialDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath);

            //load starfield & nebula background cells, put into list
            LoadTiles("Images\\StarField.bmp", _starfield);
            LoadTiles("Images\\Nebula.bmp", _nebula);

            //create side panels
            _pnlSystem = new StarSystemPanel();
            _pnlShip = new StarShipPanel();
            _pnlBuild = new BuildStarShipPanel();
            _pnlInfo = new InfoPanel();
            _pnlCommand = new CommandPanel();
            _pnlChat = new ChatPanel();
            _pnlAlliances = new AlliancePanel();
            _pnlExit = new ExitGamePanel();
        }

        //determine the "command mode" we're in
        public OrderType CommandMode
        {
            get
            {
                if (SidePanelMode == SidePanels.Command)
                    return _pnlCommand.OrderType;
                else
                    return OrderType.Move;
            }
        }

        //access cursor opf SpriteSurface
        public SCGPoint SurfaceCursor
        {
            get
            {
                return new SCGPoint(surface.CursorX, surface.CursorY);
            }
            set
            {
                surface.CursorX = value.X;
                surface.CursorY = value.Y;
            }
        }

        #region ISVHost

        public void StarShipCreated(StarShip ship)
        {
            StarShipSprite ss = new StarShipSprite(ship);
            ship.Tag = ss;
            PositionSprite(ship, ss);
            engineShips.AddSprite(ss);
        }

        public void StarShipMoved(StarShip ship, int direction, int engineSpeed)
        {
            Sprite s = (Sprite)ship.Tag;
            engineShips.MoveSprite(s, GetSpritePosition(ship), (float)engineSpeed / 3.0f);
        }

        public void ObjectMoved(SVMapObject svm, int x, int y, int engineSpeed)
        {
            Sprite s = svm.Tag as Sprite;
            if (s != null)
            {
                if (s.Engine is SpriteEngineDestination)
                {
                    SpriteEngineDestination engineDest = s.Engine as SpriteEngineDestination;
                    engineDest.MoveSprite(s, GetSpritePosition(svm), (float)engineSpeed / 3.0f);
                }
                else
                    PositionSprite(svm, s);
            }
        }

        public void StarShipDestroyed(StarShip ship)
        {
            Sprite s = (Sprite)ship.Tag;
            if (s != null)
                s.Kill();

            //remove it from selected list
            if (ShipsSelected.Contains(ship))
                ShipsSelected.Remove(ship);

            //make some explosions
            if (ship.VisibleToCurrentPlayer)
            {
                SoundFlag = SoundFlag.StarShipDestroyed;
                StarShipSprite ss = (StarShipSprite)ship.Tag;

                Color color = ship.Owner.Color.ToColor();
                Color color2 = _rnd.NextDouble() > 0.5 ? Color.White : Color.Black;
                Sprite explosion = new ParticleExplosionSprite(_rnd.Next(5) + 5, color, color2, 3, 5, _rnd.Next(20) + 30);
                explosion.Position = ss.Position;
                engineExplosions.AddSprite(explosion);

                Image img = ss.Image;
                if (img == null)
                    return;
                int particles = _rnd.Next(4) + 1;
                explosion = new BreakingBitmapExplosionSprite(img, particles, 10, 30, _rnd.Next(20) + 30);
                explosion.Position = ss.Position;
                engineExplosions.AddSprite(explosion);
            }
        }

        public void StarSystemAttacked(StarSystem system, Player attacker)
        {
            if (system.VisibleToCurrentPlayer)
            {
                Sprite explosion = new ParticleExplosionSprite(_rnd.Next(10) + 20, Color.DarkGreen, Color.Lime, 3, 5, _rnd.Next(10) + 40);
                PositionSprite(system, explosion);
                engineExplosions.AddSprite(explosion);
                explosion = new ShockWaveSprite(_rnd.Next(4) + 4, Constants.CellHalf, _rnd.Next(10) + 40, Color.DarkGreen, Color.Lime);
                PositionSprite(system, explosion);
                engineExplosions.AddSprite(explosion);
                if (system.OwnedByCurrentPlayer)
                {
                    if (system.IsCapital)
                        SoundFlag = SoundFlag.CapitalAttacked;
                    else
                        SoundFlag = SoundFlag.MyStarSystemAttacked;
                }
                else
                    SoundFlag = SoundFlag.StarSystemAttacked;

                //add a goto button
                if (system.OwnedByCurrentPlayer)
                {
                    Invoke((MethodInvoker)delegate
                    {
                        Button btn = null;
                        int lowestCounter = Int32.MaxValue;
                        foreach(Control ctl in pnlStarSystemsAttacked.Controls)
                            if (ctl.Visible)
                            {
                                SystemAttackedButtonCounter testCounter = ctl.Tag as SystemAttackedButtonCounter;
                                if (testCounter.StarSystem == system)
                                {
                                    btn = ctl as Button;
                                    break;
                                }
                            }
                        if (btn == null)
                        {
                            foreach (Control ctl in pnlStarSystemsAttacked.Controls)
                            {
                                if (!ctl.Visible)
                                {
                                    btn = ctl as Button;
                                    break;
                                }
                                SystemAttackedButtonCounter counter = ctl.Tag as SystemAttackedButtonCounter;
                                if (counter.Counter < lowestCounter)
                                {
                                    lowestCounter = counter.Counter;
                                    btn = ctl as Button;
                                }
                            }
                        }
                        SystemAttackedButtonCounter newCounter = new SystemAttackedButtonCounter();
                        newCounter.Counter = 255;
                        newCounter.StarSystem = system;
                        int green = system.IsCapital ? 0 : 255;
                        Color c = Color.FromArgb(255, green, 0);
                        btn.FlatAppearance.BorderColor = c;
                        btn.ForeColor = c;
                        btn.FlatAppearance.MouseDownBackColor = Color.FromArgb(128, green / 2, 0);
                        btn.Tag = newCounter;
                        btn.Text = system.Name;
                        btn.Visible = true;
                    });
                }
            }
        }

        public void WormholeTraveled(StarShip ship)
        {
            StarShipSprite ss = (StarShipSprite)ship.Tag;
            PositionSprite(ship, ss);
            engineShips.StopSprite(ss);
            if (ship.OwnedByCurrentPlayer)
                SoundFlag = SoundFlag.WormholeTravelled;
        }

        public void StarShipOrderAssigned(StarShip ship)
        {
            //NOP
        }

        public void StarShipOrderCleared(StarShip ship)
        {
            //NOP
        }

        public void StarSystemConquered(StarSystem system)
        {
            if (system.OwnedByCurrentPlayer)
                SoundFlag = SoundFlag.StarSystemConquered;
        }

        public void StarShipDamaged(StarShip ship)
        {
            //Create damage explosion when StarShip damaged
            if (!ship.VisibleToCurrentPlayer)
                return;
            Sprite explosion = new ParticleExplosionSprite(_rnd.Next(4) + 4, Color.Gray, Color.White, _rnd.Next(2) + 2, _rnd.Next(4) + 2, _rnd.Next(20) + 20);
            Sprite ss = (Sprite)ship.Tag;
            explosion.Position = ss.Position;
            engineExplosions.AddSprite(explosion);
            SoundFlag = SoundFlag.StarShipDamaged;
        }

        public void CloakedShipsDetected(CloakDetector ship)
        {
            if (ship.OwnedByCurrentPlayer)
                SoundFlag = SoundFlag.CloakedShipDetected;
        }

        public void StarShipOwnerChanged(StarShip ship)
        {
            //NOP
        }

        public void DisplayMessage(string message)
        {
            Invoke((MethodInvoker)delegate
            {
                pnlMessage.Visible = true;
                lblMessage.Text = message;
                lblMessage.ForeColor = Color.Aqua;
                lblMessage.Refresh();
            });
        }
        public void DisplayMessage(string message, bool top, Color color)
        {
            Invoke((MethodInvoker)delegate
            {
                if (top)
                {
                    lblPlayerStatus.Text = message;
                    lblPlayerStatus.ForeColor = color;
                    lblPlayerStatus.Visible = true;
                    lblPlayerStatus.Refresh();
                }
                else
                {
                    pnlMessage.Visible = true;
                    lblMessage.Text = message;
                    lblMessage.ForeColor = color;
                    lblMessage.Refresh();
                }
            });
        }

        public void ObjectRelocated(SVMapObject svm)
        {
            if (svm.Tag != null)
            {
                Sprite s = svm.Tag as Sprite;
                PositionSprite(svm, s);
            }
        }

        public void CreateExplosion(int x, int y, int particles, SCGColor colorStart, SCGColor colorEnd, int diamStart, int diamEnd, int lifeSpan, bool playSound)
        {
            Sprite explosion = new ParticleExplosionSprite(particles, colorStart.ToColor(), colorEnd.ToColor(), diamStart, diamEnd, lifeSpan);
            explosion.Position = new Point(x * Constants.CellSize + Constants.CellHalf, y * Constants.CellSize + Constants.CellHalf);
            engineExplosions.AddSprite(explosion);
            if (playSound)
                SoundFlag = SoundFlag.Explosion;
        }

        public void TerrainChanged(int x, int y, char terrain)
        {
            if (terrain == ' ' || terrain == 'n')
                _starfieldTiles[x, y] = _starfield.RandomValue;
            else
                _starfieldTiles[x, y] = _nebula.RandomValue;
        }

        public void ObjectRemoved(SVMapObject svm)
        {
            if (svm.Tag != null)
            {
                Sprite s = svm.Tag as Sprite;
                s.Kill();
            }
        }

        public void PlayerEliminated(Player player)
        {
            if (MainForm.GameCoordinator.Active)
            {
                MainForm.GameCoordinator.RemoveParticipant(MainForm.Prism.FindUser(player.Name));
                Invoke((MethodInvoker)delegate
                {
                    string s = player.Surrendered ? " surrendered!" : " was eliminated!";
                    DisplayMessage(player.Name + s, true, Color.Red);
                });
            }
        }

        public void BeamAttack(StarShip ship, StarShip target)
        {
            if (ship.DiscoveredByCurrentPlayer && ship.VisibleToCurrentPlayer)
                SoundFlag = SoundFlag.BeamFired;
        }

        public void BrainSendChat(Player player, ChatChannel cc, string msg)
        {
            Invoke((MethodInvoker)delegate
            {
                GameChat(player, cc, msg);
            });
        }

        public void AllianceChanged(Player p1, Player p2)
        {
            Invoke((MethodInvoker)delegate
            {
                btnAlliance.BackColor = Color.White;
                btnAlliance.Refresh();
            });
        }

        public void StarSystemCreated(StarSystem sys)
        {
            StarSystemSprite ss = new StarSystemSprite(sys);
            sys.Tag = ss;
            PositionSprite(sys, ss);
            engineSystems.AddSprite(ss);
        }

        public void MapObjectCreated(SVMapObject svm)
        {
            Sprite s = null;
            if (svm is Wormhole)
            {
                s = new WormholeSprite(svm as Wormhole, _wormHoleImage);
            }
            else if (svm is Pulsar)
            {
                s = new PulsarSprite(svm as Pulsar, _pulsarImage);
            }
            else if (svm is BlackHole)
            {
                s = new BlackHoleSprite(svm as BlackHole);
            }
            else
                throw new ArgumentException("Unexpected type in MapObjectCreated: " + svm.GetType().ToString());
            svm.Tag = s;
            PositionSprite(svm, s);
            engineSystems.AddSprite(s);
        }

        public void Pause()
        {
            Invoke((MethodInvoker)delegate
            {
                MainForm.GameCoordinator.Paused = true;
                btnPause.Enabled = false;
                btnResume.Enabled = true;
            });
        }

        public void CreateGate(Wormhole wh)
        {
            JumpGateSprite jgs = new JumpGateSprite();
            wh.Tag = jgs;
            PositionSprite(wh, jgs);
            engineSystems.AddSprite(jgs);
        }

        public void UDOCreated(UDO udo)
        {
            CreateUDOSprite(udo);
        }

        public void StarShipEmbarked(StarShip ship, StarShip carrier)
        {
            //move the sprite into the carrier at top speed
            Sprite s = (Sprite)ship.Tag;
            Sprite c = (Sprite)carrier.Tag;
            engineShips.MoveSprite(s, c.Position, 20.0f / 3.0f);
        }

        public void StarShipLaunched(StarShip ship, StarShip carrier)
        {
            //propel the sprite out of the carrier at top speed
            Sprite s = (Sprite)ship.Tag;
            Sprite c = (Sprite)carrier.Tag;
            s.Position = c.Position;
            s.Visible = true;
            int destX = ship.X * Constants.CellSize + Constants.CellHalf;
            int destY = ship.Y * Constants.CellSize + Constants.CellHalf;
            engineShips.MoveSprite(s, new Point(destX, destY), 20.0f / 3.0f);
        }

        public void StarSystemConverted(StarSystem sys, Player p)
        {
            if (p == Game.CurrentPlayer)
                SoundFlag = SoundFlag.ConvertedStarSystem;
        }

        #endregion

        //load background tiles
        private void LoadTiles(string fileName, List<Image> lst)
        {
            GamePieceBitmapFactory tiles = new GamePieceBitmapFactory();
            tiles.MasterBitmap = (Bitmap)Bitmap.FromFile(fileName);
            tiles.CellsX = tiles.MasterBitmap.Width / Constants.CellSize;
            tiles.CellsY = tiles.MasterBitmap.Height / Constants.CellSize;
            for (int x = 0; x < tiles.CellsX; x++)
                for (int y = 0; y < tiles.CellsY; y++)
                {
                    Image tile = tiles.GetGamePieceBitmap(x, y);
                    lst.Add(tile);
                }
        }
        
        //render background tiles
        private void surface_BeforeSpriteRender(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            int cellY = surface.OffsetY / Constants.CellSize;
            int drawY = 0;
            int modY = surface.OffsetY % Constants.CellSize;
            if (modY > 0)
            {
                drawY = -modY;
            }
            while (drawY < surface.Height)
            {
                int cellX = surface.OffsetX / Constants.CellSize;
                int drawX = 0;
                int modX = surface.OffsetX % Constants.CellSize;
                if (modX > 0)
                {
                    drawX -= modX;
                }
                while (drawX < surface.Width)
                {
                    Image img = _starfieldTiles[cellX, cellY];
                    g.DrawImageUnscaled(img, drawX, drawY);
                    cellX++;
                    drawX += Constants.CellSize;
                }
                cellY++;
                drawY += Constants.CellSize;
            }
        }

        //drag viewport
        private bool _dragging = false;
        private void miniMap_MouseDown(object sender, MouseEventArgs e)
        {
            _dragging = true;
            miniMap.Capture = true;
            DragViewport(e.X, e.Y);
        }
        private void miniMap_MouseMove(object sender, MouseEventArgs e)
        {
            if (_dragging)
            {
                DragViewport(e.X, e.Y);
            }
        }
        private void miniMap_MouseUp(object sender, MouseEventArgs e)
        {
            DragViewport(e.X, e.Y);
            _dragging = false;
            miniMap.Capture = false;
        }
        private void DragViewport(int x, int y)
        {
            double xmult = (double)Game.Width / (double)miniMap.Width;
            double ymult = (double)Game.Height / (double)miniMap.Height;
            int xcenter = (int)(x * xmult);
            int ycenter = (int)(y * ymult);
            surface.CenterOnCell(xcenter, ycenter);
            miniMap.Refresh();
        }

        //clicked a cell
        private void surface_CellClicked(object sender, CellEventArgs e)
        {
            if (_ignoreNextCellClick)
            {
                _ignoreNextCellClick = false;
                return;
            }

            surface.CursorX = e.X;
            surface.CursorY = e.Y;
            SVMapObject svm = Game.GetObjectAt(e.X, e.Y);
            if (svm != null &&  (!svm.VisibleToCurrentPlayer))
                if (!(svm is StarSystem))
                    svm = null;

            //are we in a special command mode?
            if (SidePanelMode == SidePanels.Command)
            {
                switch (_pnlCommand.OrderType)
                {
                    case OrderType.SetViewPoint:
                        foreach (StarShip ship in ShipsSelected)
                            if (ship.CanExecuteOrder(OrderType.SetViewPoint))
                                SubmitOrder(OrderType.SetViewPoint, ship, e.X, e.Y);
                        SidePanelMode = SidePanels.Blank;
                        break;
                    case OrderType.Unload:
                        if (ValidateTransportTarget(svm))
                        {
                            foreach (StarShip ship in ShipsSelected)
                                if (ship.CanExecuteOrder(OrderType.Unload))
                                    SubmitOrder(OrderType.Unload, ship, svm);
                            SidePanelMode = SidePanels.Blank;
                        }
                        break;
                    case OrderType.Transport:
                        if (ValidateTransportTarget(svm))
                        {
                            TransportPoints.Add(svm);
                            if (_autoCompleteTransport)
                            {
                                foreach (StarShip ship in ShipsSelected)
                                    if (ship.CanExecuteOrder(OrderType.Transport))
                                        SubmitTransportOrder(ship);
                                SidePanelMode = SidePanels.Blank;
                            }
                            else
                            {
                                _pnlCommand.Error = "";
                                _pnlCommand.ImpulseUpdate();
                            }
                        }
                        break;
                    case OrderType.Patrol:
                        if (svm != null && !svm.CanPatrolInto)
                            _pnlCommand.Error = "Cannot place Patrol Waypoint onto " + svm.DisplayName + ".";
                        else
                        {
                            Waypoints.Add(new SCGPoint(e.X, e.Y));
                            _pnlCommand.Error = "";
                            _pnlCommand.ImpulseUpdate();
                        }
                        break;
                    case OrderType.Escort:
                        if (!(svm is StarShip))
                            _pnlCommand.Error = "Click a StarShip to Escort.";
                        else
                            TargetClickedStarShip(svm as StarShip);
                        break;
                    case OrderType.Defend:
                        if (svm == null)
                        {
                            foreach (StarShip ship in ShipsSelected)
                                if (ship.CanExecuteOrder(OrderType.Defend))
                                    SubmitOrder(OrderType.DefendPoint, ship, e.X, e.Y);
                        }
                        else
                        {
                            foreach (StarShip ship in ShipsSelected)
                                if (ship.CanExecuteOrder(OrderType.Defend))
                                    SubmitOrder(OrderType.Defend, ship, svm);
                        }
                        SidePanelMode = SidePanels.Blank;
                        break;
                    default:
                        throw new ArgumentException("Unexpected OrderType: " + _pnlCommand.OrderType);
                }
            }
            //no - normal command processing
            else if (svm == null)
            {
                //nothing clicked - can we command a starship?
                if (SidePanelMode == SidePanels.StarShip)
                    if (ShipsSelected.Count > 0)
                        if (ShipsSelected[0].OwnedByCurrentPlayer)
                            foreach(StarShip ship in ShipsSelected)
                                if (ship.CanExecuteOrder(OrderType.Move))
                                    SubmitOrder(OrderType.Move, ship, e.X, e.Y);

                ClearSelectedShips();
                SidePanelMode = SidePanels.Info;
            }
            else if (svm is StarSystem)
            {
                //StarSystem clicked
                SystemSelected = svm as StarSystem;

                //can we target it?
                if (SidePanelMode == SidePanels.StarShip)
                    if (ShipsSelected.Count > 0)
                        if (ShipsSelected[0].OwnedByCurrentPlayer)
                            foreach(StarShip ship in ShipsSelected)
                                if (ship.CanTargetStarSystem(SystemSelected, true))
                                    SubmitOrder(OrderType.TargetStarSystem, ship, SystemSelected);

                ClearSelectedShips();
                SidePanelMode = SidePanels.StarSystem;
            }
            else if (svm is StarShip)
            {
                //StarShip clicked
                StarShip ship = svm as StarShip;
                if (!TargetClickedStarShip(ship))
                {
                    ClearSelectedShips();
                    SelectStarShip(ship);
                    SidePanelMode = SidePanels.StarShip;
                }
            }
            else
            {
                //something else clicked, allows ships to move there
                if (SidePanelMode == SidePanels.StarShip)
                    if (ShipsSelected.Count > 0)
                        if (ShipsSelected[0].OwnedByCurrentPlayer)
                            foreach (StarShip ship in ShipsSelected)
                                if (ship.CanExecuteOrder(OrderType.Move))
                                    SubmitOrder(OrderType.Move, ship, svm.X, svm.Y);

                SidePanelMode = SidePanels.Info;
            }
        }

        //validate a transport order target
        private bool _autoCompleteTransport = false;
        private bool ValidateTransportTarget(SVMapObject svm)
        {
            _autoCompleteTransport = false;
            if (svm == null || (!((svm is StarSystem) || (svm is StarShip))))
            {
                _pnlCommand.Error = "Click one of your StarSystems" + _pnlCommand.GetResourceStarShipString() + ".";
                return false;
            }
            else if (svm is StarShip)
            {
                StarShip ship = svm as StarShip;
                if (!ship.OwnedByCurrentPlayer)
                {
                    _pnlCommand.Error = "StarShip must be owned by you, and be able to carry Resources.";
                    return false;
                }
                else if (!(ship is ResourceStarShip))
                {
                    _pnlCommand.Error = "StarShip must be able to carry Resources.";
                    return false;
                }
                else
                {
                    //check sources and if valid "destination only" selected, auto-complete
                    ResourceStarShip rss = ship as ResourceStarShip;
                    if (rss.IsTransportSource)
                        return true;
                    if (TransportPoints.Count == 0)
                    {
                        _pnlCommand.Error = "This StarShip cannot serve as a Transport Source, it is a Destination only.";
                        return false;
                    }
                    else
                    {
                        //auto-complete
                        _autoCompleteTransport = true;
                        return true;
                    }
                }
            }
            else if (svm is StarSystem)
            {
                StarSystem sys = svm as StarSystem;
                if (!sys.OwnedByCurrentPlayer)
                {
                    _pnlCommand.Error = "StarSystem must be owned by you.";
                    return false;
                }
                else
                    return true;
            }
            return false;
        }

        //target clicked starship
        private bool TargetClickedStarShip(StarShip target)
        {
            bool targeted = false;
            if (SidePanelMode == SidePanels.StarShip || SidePanelMode == SidePanels.Command)
                if (ShipsSelected.Count > 0)
                    if (ShipsSelected[0].OwnedByCurrentPlayer)
                        foreach (StarShip ship in ShipsSelected)
                        {
                            switch (CommandMode)
                            {
                                case OrderType.Escort:
                                    if (ship.CanExecuteOrder(OrderType.Escort))
                                    {
                                        int xDiff = ship.X - target.X;
                                        int yDiff = ship.Y - target.Y;
                                        SubmitOrder(OrderType.Escort, ship, target, xDiff, yDiff);
                                        targeted = true;
                                    }
                                    break;
                                default:
                                    if (target.ShipType == StarShipType.Carrier && target.OwnedByCurrentPlayer)
                                    {
                                        Carrier carrier = target as Carrier;
                                        if (!carrier.IsFull)
                                            if (ship.CanExecuteOrder(OrderType.BoardCarrier))
                                            {
                                                SubmitOrder(OrderType.BoardCarrier, ship, target);
                                                targeted = true;
                                            }
                                    }
                                    else if (ship.CanTargetStarShip(target, true))
                                    {
                                        SubmitOrder(OrderType.TargetStarShip, ship, target);
                                        targeted = true;
                                    }
                                    break;
                            }
                        }
            if (targeted)
            {
                _ignoreNextCellClick = true;
                SidePanelMode = SidePanels.Blank;
            }
            return targeted;
        }

        //clear selected starships
        private void ClearSelectedShips()
        {
            foreach (StarShip ship in ShipsSelected)
            {
                StarShipSprite ss = (StarShipSprite)ship.Tag;
                ss.Selected = false;
            }
            ShipsSelected.Clear();
        }

        //select a starship
        private void SelectStarShip(StarShip ship)
        {
            StarShipSprite ss = (StarShipSprite)ship.Tag;
            ss.Selected = true;
            ShipsSelected.Add(ship);
        }

        //select all friendly starships in range
        private bool _ignoreNextSpriteClick = false;
        private void surface_RangeSelected(object sender, RangeSelectedEventArgs e)
        {
            ClearSelectedShips();
            if (Game.CurrentPlayer == null)
                return;
            foreach (StarShip ship in Game.CurrentPlayer.StarShips)
                if (e.SelectedRange.Contains(ship.X, ship.Y))
                    if (!ship.IsEmbarked)
                        SelectStarShip(ship);
            if (ShipsSelected.Count > 0)
            {
                _ignoreNextSpriteClick = true;
                SidePanelMode = SidePanels.StarShip;
            }
        }

        //sprite clicked
        private bool _ignoreNextCellClick = false;
        private void surface_SpriteClicked(object sender, SpriteClickEventArgs e)
        {
            if (_ignoreNextSpriteClick)
            {
                _ignoreNextSpriteClick = false;
                return;
            }

            //no need to process during certain commands
            if (SidePanelMode == SidePanels.Command)
            {
                OrderType ot = _pnlCommand.OrderType;
                if (ot == OrderType.Patrol || ot == OrderType.Defend || ot == OrderType.Transport || ot == OrderType.Unload || ot == OrderType.SetViewPoint)
                    return;
            }

            //allow clicking starships that are moving
            if (e.Sprite is StarShipSprite)
            {
                StarShipSprite ss = e.Sprite as StarShipSprite;
                StarShip ship = ss.StarShip;
                if (!ship.VisibleToCurrentPlayer)
                    return;
                if (!TargetClickedStarShip(ship))
                {
                    ClearSelectedShips();
                    SelectStarShip(ss.StarShip);
                    SidePanelMode = SidePanels.StarShip;
                    _ignoreNextCellClick = true;
                    surface.CursorX = ship.X;
                    surface.CursorY = ship.Y;
                }
            }
        }

        //after sprite renderingp
        private Graphics _g;
        private void surface_AfterSpriteRender(object sender, PaintEventArgs e)
        {
            //draw patrol waypoints
            foreach (SCGPoint pt in Waypoints)
            {
                int x = pt.X * Constants.CellSize + Constants.CellHalf - _waypointImage.Width / 2 - surface.OffsetX;
                int y = pt.Y * Constants.CellSize + Constants.CellHalf - _waypointImage.Height / 2 - surface.OffsetY;
                e.Graphics.DrawImage(_waypointImage, x, y);
            }

            //scenario-specific rendering
            if (Game != null && Game.Scenario != null)
            {
                _g = e.Graphics;
                Game.Scenario.CustomRendering(this);
                _g = null;
            }

            //final game messaging
            if (_victoryMessage != "")
            {
                Graphics g = e.Graphics;
                int x = (int)(surface.Width / 2 - g.MeasureString(_victoryMessage, _victoryFont).Width / 2);
                int y = (int)(surface.Height / 2 - g.MeasureString(_victoryMessage, _victoryFont).Height / 2);
                g.DrawString(_victoryMessage, _victoryFont, _victoryBrush, x, y);
            }
        }

        #region ISVCustomRenderer

        private static Dictionary<int, Font> _fonts = new Dictionary<int, Font>();
        public void DrawText(string text, int x, int y, int offsetX, int offsetY, SCGColor color, int fontSize)
        {
            x = x * Constants.CellSize - surface.OffsetX;
            y = y * Constants.CellSize - surface.OffsetY;
            x += offsetX;
            y += offsetY;
            _g.DrawString(text, GetFont(fontSize), PenBrushFactory.GetBrush(color), x, y);
        }

        public void DrawWrappedText(string text, SCGColor color, int fontSize)
        {
            _g.DrawString(text, GetFont(fontSize), PenBrushFactory.GetBrush(color), new RectangleF(4, 4, surface.Width - 8, surface.Width - 8));
        }

        public void DrawTextScreenCoords(string text, int x, int y, SCGColor color, int fontSize)
        {
            _g.DrawString(text, GetFont(fontSize), PenBrushFactory.GetBrush(color), x, y);
        }

        public void DrawRectangle(int x1, int y1, int x2, int y2, SCGColor color, int lineThickness)
        {
            int left = x1 * Constants.CellSize;
            int top = y1 * Constants.CellSize;
            int width = (x2 - x1 + 1) * Constants.CellSize;
            int height = (y2 - y1 + 1) * Constants.CellSize;
            Rectangle rect = new Rectangle(left, top, width, height);
            rect.Offset(-surface.OffsetX, -surface.OffsetY);
            Pen p = PenBrushFactory.GetPen(color);
            p.Width = lineThickness;
            _g.DrawRectangle(p, rect);
            p.Width = 1;
        }

        public void FillRectangle(int x1, int y1, int x2, int y2, SCGColor color, SCGColor fillColor, int lineThickness)
        {
            int left = x1 * Constants.CellSize;
            int top = y1 * Constants.CellSize;
            int width = (x2 - x1 + 1) * Constants.CellSize;
            int height = (y2 - y1 + 1) * Constants.CellSize;
            Rectangle rect = new Rectangle(left, top, width, height);
            rect.Offset(-surface.OffsetX, -surface.OffsetY);
            _g.FillRectangle(PenBrushFactory.GetBrush(fillColor), rect);
            Pen p = PenBrushFactory.GetPen(color);
            p.Width = lineThickness;
            _g.DrawRectangle(p, rect);
            p.Width = 1;
        }

        public void DrawImage(object img, int x, int y, int offsetX, int offsetY)
        {
            Image image = img as Image;
            if (image != null)
            {
                x *= Constants.CellSize;
                x -= surface.OffsetX;
                y *= Constants.CellSize;
                y -= surface.OffsetY;
                _g.DrawImageUnscaled(image, x + offsetX, y + offsetY);
            }
        }

        private Font GetFont(int size)
        {
            if (_fonts.ContainsKey(size))
                return _fonts[size];
            else
            {
                Font font = new Font(MainForm.FontFamily, size);
                _fonts[size] = font;
                return font;
            }
        }

        #endregion

        //clear message
        private void lblMessage_Click(object sender, EventArgs e)
        {
            pnlMessage.Visible = false;
        }

        //center on a starsystem
        private void CenterStarSystem(StarSystem sys)
        {
            surface.CenterOnCell(sys.X, sys.Y);
            surface.CursorX = sys.X;
            surface.CursorY = sys.Y;
            SystemSelected = sys;
            _pnlSystem.ImpulseUpdate();
            SidePanelMode = SidePanels.StarSystem;
        }

        //center on capital
        private void btnCapital_Click(object sender, EventArgs e)
        {
            if (Game.CurrentPlayer != null)
                if (Game.CurrentPlayer.Capital != null)
                {
                    StarSystem sys = Game.CurrentPlayer.Capital;
                    CenterStarSystem(sys);
                }
        }

        //grid?
        private void btnGrid_DownStateChanged(object sender, EventArgs e)
        {
            surface.GridVisible = btnGrid.Down;
        }

        //pause
        private void btnPause_Click_1(object sender, EventArgs e)
        {
            btnPause.Visible = false;
            btnResume.Visible = true;
            btnSave.Visible = true;
            MainForm.GameCoordinator.Paused = true;
            pnlTop.Refresh();
        }

        //resume
        private void btnResume_Click(object sender, EventArgs e)
        {
            btnResume.Visible = false;
            btnPause.Visible = true;
            btnSave.Visible = false;
            MainForm.GameCoordinator.Paused = false;
            pnlTop.Refresh();
        }

        //when embarking sprites reach the carrier, make them disappear
        private void engineShips_SpriteReachedDestination(object sender, SpriteEventArgs e)
        {
            Sprite s = e.Sprite;
            if (s is StarShipSprite)
            {
                StarShip ship = s.Tag as StarShip;
                if (ship.IsEmbarked)
                    s.Visible = false;
            }
        }

        //starsystem attacked - go there!
        private void btnSytemAttacked1_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            SystemAttackedButtonCounter counter = btn.Tag as SystemAttackedButtonCounter;
            CenterStarSystem(counter.StarSystem);
        }

        //save game
        private void btnSave_Click(object sender, EventArgs e)
        {
            if (dlgSave.ShowDialog(MainForm) == DialogResult.OK)
            {
                string s = Game.Persist();
                string fileName = dlgSave.FileName;
                File.WriteAllText(fileName, s);
                MessageBox.Show("Game saved to: " + fileName);
            }
        }

        //hide player status
        private void lblPlayerStatus_Click(object sender, EventArgs e)
        {
            lblPlayerStatus.Visible = false;
        }

        //chat
        private void btnChat_Click(object sender, EventArgs e)
        {
            SidePanelMode = SidePanels.Communications;
            btnChat.BackColor = Color.Black;
            btnChat.Refresh();
        }

        //alliances
        private void btnAlliance_Click(object sender, EventArgs e)
        {
            SidePanelMode = SidePanels.Alliances;
            btnAlliance.BackColor = Color.Black;
            btnAlliance.Refresh();
        }

        //quit the game
        public void QuitGame()
        {
            if (Game.IsActiveMultiPlayer)
                SubmitOrder(OrderType.Surrender, Game.CurrentPlayer);
            else
                CleanupGame();
        }

        //perform post-game cleanup
        public void CleanupGame()
        {
            MainForm.GameCoordinator.Stop();
            surface.Active = false;
            engineExplosions.Clear();
            engineImages.Clear();
            engineSystems.Clear();
            _transportPoints.Clear();
            _waypoints.Clear();
            ClearSelectedShips();
            MainForm.Game = null;
            miniMap.Game = null;
            if (MainForm.Prism.LoggedIn)
            {
                MainForm.ShowPage(Pages.Lobby);
                MainForm.Prism.EnterRoom("Lobby");
            }
            else
                MainForm.ShowPage(Pages.Title);
        }

        //exit game
        private void btnExit_Click(object sender, EventArgs e)
        {
            if (MainForm.GameCoordinator.Active)
                SidePanelMode = SidePanels.QuitConfirm;
            else
                CleanupGame();
        }
    }

    //side panel modes
    public enum SidePanels { Blank, StarSystem, StarShip, Build, Info, Command, SetAutoBuildStarShip,
        StarShipBuild, Communications, Alliances, QuitConfirm }

    //Sound for the impulse
    public enum SoundFlag { None, StarShipDamaged, StarShipDestroyed, StarSystemAttacked, StarSystemConquered, 
        CloakedShipDetected, BeamFired, WormholeTravelled, MyStarSystemAttacked, Explosion, ConvertedStarSystem,
        CapitalAttacked };

    //used to store which starsystem a system-attacked goto button refers to
    internal class SystemAttackedButtonCounter
    {
        internal StarSystem StarSystem;
        internal int Counter;
    }
}
